home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / ddj0492.zip / BTC.ASC < prev    next >
Text File  |  1992-03-10  |  9KB  |  293 lines

  1. _BLOCK TRUNCATION COMPRESSION_
  2. by Anton Kruger
  3.  
  4. [LISTING ONE]
  5.  
  6. /* File: btc4x4.c -- Author: Anton Kruger -- Revision: 1.0
  7.  * Copyright (c) Truda Software
  8.  * 215 Marengo Rd, #2, Oxford, IA 52322-9383
  9.  * Description: Contains routines for performing 4x4 block truncation 
  10.  * compression on 8-bit, 256x256 monochrome images.
  11.  * Compilers:   MSC 5.1. 
  12.  */
  13.                       /* *** Headers *** */
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <math.h>
  17.  
  18.                /* *** Typedefs and defines *** */          
  19. typedef unsigned char byte;   
  20. typedef unsigned int  word;
  21. #define IOBUFFSIZE 2048       /* size of i/o buffers */
  22.  
  23.                /* *** Function prototypes *** */
  24. void main(int argc, char *argv[]);
  25. void btc4x4(FILE *fp1, FILE * fp2);
  26. void GetStats(byte * block,byte *a,byte *b,byte *mean);
  27. int  GetBlock(byte *block, FILE *fp);
  28. void PutCode(byte a, byte b, word code, FILE *fp);
  29. void inform(char *mess);
  30.  
  31. void main(int argc, char *argv[])
  32. {
  33.    /* A short driver routine for "btc4x4.c", that performs block truncation 
  34.    ** compression on an image file. */
  35.    FILE        *fp1,*fp2;
  36.    if (argc < 3){
  37.       inform("Usage: BTC4x4 infile outfile\n\n");
  38.       inform("infile is a 256x256 binary image file\n");
  39.       inform("outfile is a BTC-compressed file\n");
  40.       exit(-1);
  41.    }
  42.    if ((fp1 = fopen(argv[1],"rb")) == NULL) {
  43.       inform("ERROR: Could not open input file: ");
  44.       inform(argv[1]);
  45.       exit(-1);
  46.    }
  47.    setvbuf(fp1,(char *)NULL,_IOFBF,IOBUFFSIZE);
  48.    if ((fp2 = fopen(argv[2],"wb")) == NULL) {
  49.       inform("ERROR: Could not open output file: ");
  50.       inform(argv[2]);
  51.       exit(-1);
  52.    }
  53.    setvbuf(fp2,(char *)NULL,_IOFBF,IOBUFFSIZE);
  54.    inform("Block Truncation Compression.\n");
  55.    inform(argv[1]); inform(" -> "); inform(argv[2]);
  56.    inform("\nPlease wait...\n");
  57.  
  58.    btc4x4(fp1, fp2);
  59.  
  60.    fclose(fp1);
  61.    fclose(fp2);
  62.    inform("Done!\n");
  63.    exit(0);
  64. }
  65. void btc4x4(FILE *fp1, FILE * fp2)
  66. {
  67.    /* Block truncation compress the file connected to "fp1". The output goes 
  68.    ** to the file connected to "fp2". */
  69.    int         i;
  70.    byte        a,b,mean;
  71.    byte        block[16];
  72.    word        code;
  73.    while (GetBlock(block,fp1) != EOF){
  74.       GetStats(block,&a,&b,&mean);
  75.       code = 0;                       /*  clear bits */   
  76.       for (i=0;i<=15;i++)
  77.          if (block[i] >= mean)
  78.             code = code | (1<<i);     /* set bit "i" */
  79.       PutCode(a,b,code,fp2);
  80.    }
  81. }
  82. void GetStats(byte * block,byte *a,byte *b,byte *mean)
  83. {
  84.    /* This routine computes the statistics "a", "b", and "mean" for the pixels 
  85.    ** in "block". */
  86.    int         i,q;
  87.    float       m1,m2,sigma;
  88.    float       atmp,btmp;
  89.    double      d;
  90.  
  91.    /* Compute mean, mean-square, and "sigma". */
  92.    m1 = m2 = (float)0.0;
  93.    for (i=0;i<=15;i++){
  94.       m1 = m1 + (float)block[i];
  95.       m2 = m2 + (float)(block[i]*block[i]);
  96.    }
  97.    m1 = m1/16.0;
  98.    m2 = m2/16.0;
  99.    sigma = (float)sqrt((double)(m2- m1*m1));
  100.    
  101.    /* Count "q", the number of pixels >= "mean" , then compute "a", and "b". */
  102.    for (q=0,i=0;i<=15;i++)
  103.       if ((float)block[i] >= m1) q++;
  104.    if (q == 16){
  105.       *mean = (byte)(m1+0.5);
  106.       *a = *b = *mean;    /* all pixels are the same */
  107.    }
  108.    else{
  109.       d  = sqrt((double)q/(16.0-q));
  110.       atmp = m1 - sigma*d;
  111.       btmp = m1 + sigma/d;
  112.       if (atmp < (float)0) atmp = (float)0;
  113.       if (btmp > (float)255) btmp = (float)255;
  114.  
  115.       /* Round values to nearest integer */
  116.       *a = (byte)(0.5+atmp);  
  117.       *b = (byte)(0.5+btmp);
  118.       *mean = (byte)(m1+0.5);
  119.    }
  120. }
  121. int GetBlock(byte *block, FILE *fp)
  122. {
  123.    /* This routine gets a block of 4x4 pixels from the file connected to "fp". 
  124.    ** Normally it returns 1. If at EOF, or errors occur, it returns  EOF. */
  125.    static int  bp = 256;
  126.    static byte buffer[4][256];
  127.    int         i,j;
  128.  
  129.    /* If the 4-line buffer is empty, fill it. If it cannot be filled for some 
  130.    ** reason, return EOF. Otherwise, reset the buffer pointer "bp". */
  131.    if (bp == 256){
  132.       for (j=0;j<=3;j++)
  133.          if (fread(buffer[j],1,256,fp) != 256)
  134.             return(EOF);
  135.       bp = 0;
  136.    }
  137.  
  138.    /* Get 16 pixels from the 4-line buffer. Then update the buffer 
  139.    ** pointer "bp", and return to caller. */
  140.    for (j=0;j<=3;j++)
  141.       for (i=0;i<=3;i++)
  142.          block[i+4*j] = buffer[j][bp+i];
  143.    bp = bp+4;
  144.    return(1);
  145. }
  146. void PutCode(byte a, byte b, word code, FILE *fp)
  147. {
  148.    /* This routine writes "a", "b", and the block truncation "code" to 
  149.    ** the file connected to "fp". */
  150.    fputc((byte)a,fp);
  151.    fputc((byte)b,fp);
  152.    fputc((byte)(code & 255),fp);       /* LSB first  */
  153.    fputc((byte)((code>>8) & 255),fp);  /* MSB second */
  154. }
  155. void inform(char *mess)
  156. {
  157.    fprintf(stderr,"%s",mess);
  158. }
  159.  
  160.  
  161. [LISTING TWO]
  162.  
  163. /* File:  btd4x4.c -- Author: Anton Kruger -- Revision: 1.0
  164.  * Copyright (c) Truda Software
  165.  * 215 Marengo Rd, #2, Oxford, IA 52322-9383
  166.  * Description: Contains routines for performing 4x4 block truncation 
  167.  *  decompression; assumes input files were compressed with "btc4x4".
  168.  * Compilers:   MSC 5.1. 
  169.  */
  170.                       /* *** Headers *** */
  171. #include <stdio.h>
  172. #include <stdlib.h>
  173. #include <math.h>
  174.  
  175.                /* *** Typedefs and defines *** */          
  176. typedef unsigned char byte;   
  177. typedef unsigned int  word;
  178. #define IOBUFFSIZE 2048       /* size of i/o buffers */
  179.  
  180.                /* *** Function prototypes *** */
  181. void main(int argc, char *argv[]);
  182. void btd4x4(FILE *fp1, FILE * fp2);
  183. int  GetCode(byte *a, byte *b, word * code, FILE *fp);
  184. int  PutBlock(byte *block, FILE *fp);
  185. void inform(char *mess);
  186.  
  187. void main(int argc, char *argv[])
  188. {
  189.    /* A diver routine for "btd4x4.c", that decompresses a block truncation 
  190.    ** compressed file. */
  191.    FILE        *fp1,*fp2;
  192.  
  193.    if (argc < 3){
  194.       inform("Usage: BTD4x4 infile outfile\n\n");
  195.       inform("infile is a BTC-compressed file\n");
  196.       inform("outfile is a 256x256 binary image file\n");
  197.       exit(-1);
  198.    }
  199.    if ((fp1 = fopen(argv[1],"rb")) == NULL) {
  200.       inform("ERROR: Could not open input file: ");
  201.       inform(argv[1]);
  202.       exit(-1);
  203.    }
  204.    setvbuf(fp1,(char *)NULL,_IOFBF,IOBUFFSIZE);
  205.    if ((fp2 = fopen(argv[2],"wb")) == NULL) {
  206.       inform("ERROR: Could not open output file: ");
  207.       inform(argv[2]);
  208.       exit(-1);
  209.    }
  210.    setvbuf(fp2,(char *)NULL,_IOFBF,IOBUFFSIZE);
  211.  
  212.    inform("Block Truncation Decompression.\n");
  213.    inform(argv[1]); inform(" -> "); inform(argv[2]);
  214.    inform("\nPlease wait...\n");
  215.  
  216.    btd4x4(fp1, fp2);
  217.  
  218.    fclose(fp1);
  219.    fclose(fp2);
  220.    inform("Done!\n");
  221.    exit(0);
  222. }
  223. void btd4x4(FILE *fp1, FILE * fp2)
  224. {
  225.    /* Decompress the block truncation compressed file connected to "fp1". 
  226.    ** The output goes to the file connected to "fp2". */
  227.    int         i;
  228.    byte        a,b;
  229.    byte        block[16];
  230.    word        code;
  231.  
  232.    while (GetCode(&a,&b,&code,fp1) != EOF){
  233.       for (i=0;i<=15;i++)
  234.          if (code & (1 << i))    /* is bit "i" set ? */
  235.             block[i] = b;
  236.          else
  237.             block[i] = a;
  238.       PutBlock(block,fp2);
  239.    }
  240.    /* The 4-line buffer maintained by "PutBlock" should be full at this point.  
  241.    ** Output one last dummy block. This will not be written to the output
  242.    ** file, and only serves to flush that buffer. */
  243.    PutBlock(block,fp2);
  244. }
  245.  
  246. int PutBlock(byte *block, FILE *fp)
  247. {
  248.    /* This routine writes a block of 4x4 pixels to the file connected to "fp". 
  249.    ** Normally it returns 1. If at EOF, or errors occur, it returns EOF. */
  250.    static int  bp = 0;
  251.    static byte buffer[4][256];
  252.    int         i,j;
  253.  
  254.    /* If the 4-line buffer is full, flush it. If it cannot be flushed for some 
  255.    ** reason, return EOF. Otherwise, reset the buffer pointer "bp". */
  256.    if (bp == 256){
  257.       for (j=0;j<=3;j++)
  258.          if (fwrite(buffer[j],1,256,fp) != 256)
  259.             return(EOF);
  260.       bp = 0;
  261.    }
  262.  
  263.    /* Place 16 pixels in the 4-line buffer. Then update the buffer pointer 
  264.    ** "bp", and return to caller. */
  265.    for (j=0;j<=3;j++)
  266.       for (i=0;i<=3;i++)
  267.          buffer[j][bp+i] = block[i+4*j];
  268.    bp = bp+4;
  269.    return(1);
  270. }
  271.  
  272. int  GetCode(byte *a, byte *b, word * code, FILE *fp)
  273. {
  274.    /* This routine gets "a", "b", and the block truncation "code" from the 
  275.    ** file connected to "fp". Normally it returns 1. If at end of file, or
  276.    ** errors occur, it returns EOF. */
  277.    *a = (byte)fgetc(fp);
  278.    *b = (byte)fgetc(fp);
  279.    *code = fgetc(fp);                  /* LSB first  */
  280.    *code = (fgetc(fp) << 8) + *code;   /* MSB second */
  281.    if (feof(fp) || ferror(fp))
  282.       return(EOF);
  283.    else
  284.       return(1);         
  285. }
  286. void inform(char *mess)
  287. {
  288.    fprintf(stderr,"%s",mess);
  289. }
  290.  
  291.  
  292.  
  293.